home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Games Collection 1
/
software vault.zip
/
software vault
/
CDR10
/
ACK3D.ZIP
/
DEMO
/
DEMO.C
< prev
next >
Wrap
Text File
|
1993-08-24
|
60KB
|
2,660 lines
/*********************( Animation Construction Kit Demo )**********************/
/* Lary Myers */
/* */
/* Okay, don't laugh, this program started out to be a tutorial on using the */
/* functions in the ACK3D library but then grew and grew, and grew! Now it's */
/* a coalage of routines, experiments, half-wit ideas, etc. I think what I */
/* wanted to do was see if the engine itself could be used in a large scale */
/* game. While Station Escape doesn't come close to commercial (or even */
/* shareware) quality, it does demonstrate that the engine can be used to */
/* produce something other than quick demo's. You are welcome to hack away */
/* at this code, or toss it completely and start anew. I'm putting this into */
/* the public domain "as-is" for everyone to share. Maybe it will spark some */
/* ideas for other games that then go on to be BIG sellers! If so, then I */
/* will be pleased to know that I helped in some way towards new games. */
/* */
/* Thank You for looking at the ACK demonstration and engine. */
/* */
/* Lary Myers CIS account 72355,655 */
/*****************************< ACK-3D >***********************************/
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <mem.h>
#include <alloc.h>
#include <io.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <conio.h>
#include <ctype.h>
#include <sys\stat.h>
#include "ack3d.h"
#include "acksnd.h"
#include "demo.h"
/* Variables in the DEMORD.C module */
extern char GridFile[];
extern char PalFile[];
extern int ErrorCode;
/****** G L O B A L S ******************************/
ACKENG *ae; /* The main interface struct */
MOUSE mouse;
UCHAR scanCode;
UCHAR Keys[128];
int HaveMouse;
int SoundDevice; /* Selected from command line */
int Shooting;
int BoltEnergy;
int Decompress;
int MouseMode; /* 0 = UW2 style, 1 = Wolf style */
int LockedFlag;
int TotalInventory;
int InventoryFlag;
int HoloSoundFlag;
int YouWON;
VIEWERS Views[] = {
96,96,INT_ANGLE_90,
96,96,0,
96,96,INT_ANGLE_90
};
void interrupt (*oldvec)();
void interrupt myInt();
void interrupt (*OldTimer)();
void interrupt MyTimer();
UCHAR nums[] = {1,2,3,4,5,6,7,8};
UCHAR snums[] = {17,17,18,18,19,19,20,20,20,20,
19,19,18,18,17,17,17,17,17,17,
17,17,17,17,17,17,17,17};
UCHAR bnums[] = {9,9,9,10,10,11,12,13,14,15,16,
11,10,9,9,9,9,9,9,9,9,9,9,9,
9,9,9,9,9,9,9,9,9,9,9,9,9,9};
char Path[] = "bitmaps\\";
UINT VidOffset;
char tmHours;
char tmMinutes;
char tmSeconds;
int tmDelay;
int tmCounter;
int LastMouseIndex;
int OldWall;
int NewWall;
int WallDelay;
UCHAR WallType[] = {2,3,4};
UCHAR WallType1[] = {11,12,13,14};
UCHAR WallType2[] = {7,8};
UCHAR WallType3[] = {9,10};
UCHAR WallType4[] = {28,29};
UCHAR HoloWalls[] = {41,44,45,45};
UCHAR Inventory[MAX_INVENTORY+1];
int SpaceMenDelay[21];
int WallIndex;
int WallIndex1;
int WallIndex2;
int WallIndex3;
int WallIndex4;
int HoloIndex;
UCHAR far *wMaps[3];
UCHAR far *wMaps1[4];
UCHAR far *wMaps2[2];
UCHAR far *wMaps3[2];
UCHAR far *wMaps4[2];
UCHAR far *hMaps[4];
/***** Mouse cursor bitmaps ******/
unsigned Arrow[32] = {
0x3fff,0x1fff,0xfff,0x7ff,0x3ff,0x1ff,0xff,0x7f,
0x3f,0x1f,0xf,0x7,0x1847,0x387f,0xfc3f,0xfe7f,
0x0,0x4000,0x6000,0x7000,0x7800,0x7c00,0x7e00,0x7f00,
0x7f80,0x7fc0,0x7fe0,0x6730,0x4300,0x300,0x180,0x0};
unsigned UpArrow[32] = {
0xfeff,0xfc7f,0xf83f,0xf01f,0xe00f,0xc007,0xc007,0xc007,
0xc007,0xc827,0xf83f,0xf83f,0xf83f,0xf83f,0xf83f,0xf83f,
0x0,0x100,0x380,0x7c0,0xfe0,0x1ff0,0x1ff0,0x1bb0,
0x1390,0x380,0x380,0x380,0x380,0x380,0x380,0x0};
unsigned DownArrow[32] = {
0xffff,0xf83f,0xf83f,0xf83f,0xf83f,0xf83f,0xf83f,0xc827,
0xc007,0xc007,0xc007,0xe00f,0xf01f,0xf83f,0xfc7f,0xfeff,
0x0,0x0,0x380,0x380,0x380,0x380,0x380,0x380,
0x1390,0x1bb0,0x1ff0,0xfe0,0x7c0,0x380,0x100,0x0};
unsigned LeftArrow[32] = {
0xffff,0xf7ff,0xe3ff,0xc0ff,0x807f,0x3f,0x801f,0xc01f,
0xe01f,0xf41f,0xfc1f,0xfc1f,0xfc1f,0xfc1f,0xfc1f,0xfc1f,
0x0,0x0,0x800,0x1800,0x3f00,0x7f80,0x3fc0,0x19c0,
0x9c0,0x1c0,0x1c0,0x1c0,0x1c0,0x1c0,0x1c0,0x0};
unsigned RightArrow[32] = {
0xffff,0xffef,0xffc7,0xff03,0xfe01,0xfc00,0xf801,0xf803,
0xf807,0xf82f,0xf83f,0xf83f,0xf83f,0xf83f,0xf83f,0xf83f,
0x0,0x0,0x10,0x18,0xfc,0x1fe,0x3fc,0x398,
0x390,0x380,0x380,0x380,0x380,0x380,0x380,0x0};
MCURSORS mCursors[] = {
1,0,Arrow,
7,0,UpArrow,
7,15,DownArrow,
0,5,LeftArrow,
7,5,RightArrow
};
char far *SoundFiles[SOUND_MAX_INDEX+1];
char MusicFile[60];
UCHAR FontTransparent;
UCHAR FontColor;
UCHAR TextBGcolor;
UCHAR far *smFont;
UCHAR far *CompassBmp;
char *ObjectText[] = {
"Circuit Board....",
"Fuel Cells.......",
"Computer........."
};
char ObjectList[OBJECT_COUNT+1];
HOLOTEXT HoloText[] = {
HT_TEXTX,HT_TEXTY,"No program",
HT_TEXTX,HT_TEXTY+10,"Program 1",
HT_TEXTX,HT_TEXTY+20,"Program 2",
-1,-1,0
};
/****************************************************************************
** Here we load a specific DP2 brush that we'll use as our display font. **
** **
****************************************************************************/
int LoadSmallFont(void)
{
int ht,wt,len;
smFont = AckReadiff("bitmaps\\spfont.bbm");
if (smFont == NULL)
return(-1);
ht = (*(int *)smFont);
wt = (*(int *)&smFont[2]);
len = ht * wt;
memmove(smFont,&smFont[4],len);
return(0);
}
/****************************************************************************
** Displays a character either directly on the video, or into the screen **
** buffer depending on whether FontTransparent flag is set. **
** **
****************************************************************************/
void smWriteChar(int x,int y,unsigned char ch)
{
int FontOffset,VidOffset;
int row,col;
unsigned char far *Video;
VidOffset = (y * 320) + x;
Video = MK_FP(0xA000,VidOffset);
FontOffset = ((ch-32) * 5);
if (FontTransparent)
Video = ae->ScreenBuffer + VidOffset;
for (row = 0; row < 5; row++)
{
if (!FontTransparent)
memset(Video,TextBGcolor,4);
if (smFont[FontOffset])
Video[0] = FontColor;
if (smFont[FontOffset+1])
Video[1] = FontColor;
if (smFont[FontOffset+2])
Video[2] = FontColor;
if (smFont[FontOffset+3])
Video[3] = FontColor;
Video += 320;
FontOffset += 294;
}
}
/****************************************************************************
** Calls smWriteChar() to display the contents of the passed string. Only **
** crude string handling is done in this routine. **
** **
****************************************************************************/
int smWriteString(int x,int y,char *s)
{
int OrgX;
char ch;
OrgX = x;
mouse_hide_cursor();
while (*s)
{
ch = *s++;
if (ch == 10) /* If a linefeed then advance to next row */
{
x = OrgX;
y += 8;
continue;
}
if (ch < ' ')
continue;
ch = toupper(ch);
smWriteChar(x,y,ch);
x += 5; /* Advance to next character position */
}
mouse_show_cursor();
return(y);
}
/****************************************************************************
** Sets the transparent flag and then calls smWriteString() to place the **
** string into the system buffer. This routine is called after the walls **
** are drawn so the text appears to float on top of the walls. **
****************************************************************************/
void smWriteHUD(int x,int y,UCHAR color,char *s)
{
FontTransparent = 1;
FontColor = color;
smWriteString(x,y,s);
FontTransparent = 0;
FontColor = 15;
}
/****************************************************************************
** Just a quick menu pick list to allow the player to select the desired **
** holodeck program to run. **
** **
****************************************************************************/
int PickHoloProgram(void)
{
int i,mx,my,mbutton;
int prognum,x,x1,y;
UCHAR hColor;
mouse_hide_cursor();
hColor = 14;
i = 0;
while (1)
{
if (HoloText[i].x == -1)
break;
smWriteHUD(HoloText[i].x,HoloText[i].y,hColor,HoloText[i].Text);
i++;
}
AckDisplayScreen(ae);
mouse_show_cursor();
if (MouseMode)
mouse_show_cursor();
prognum = -2;
while (prognum == -2)
{
mouse_read_cursor(&mbutton,&my,&mx);
if (mbutton & 2)
{
prognum = -1;
break;
}
if (mbutton & 1)
{
i = 0;
while (1)
{
x = HoloText[i].x;
if (x == -1)
break;
y = HoloText[i].y;
x1 = (strlen(HoloText[i].Text) * 5) + x;
if (mx >= x && mx <= x1 && my >= y && my <= (y+5))
{
prognum = i;
break;
}
i++;
}
}
}
if (MouseMode)
mouse_hide_cursor();
return(prognum);
}
/****************************************************************************
** Builds the appropriate strings from the inventory array and displays **
** them on top of the current walls. **
** **
****************************************************************************/
void ShowInventory(void)
{
int i,row;
char mBuf[30];
smWriteHUD(VP_TEXTX,VP_TEXTY,2,"Inventory:");
row = 10;
for (i = 0; i < OBJECT_COUNT; i++)
{
strcpy(mBuf,ObjectText[i]);
if (ObjectList[i] != 1)
strcat(mBuf,"No");
else
strcat(mBuf,"Yes");
smWriteHUD(VP_TEXTX,VP_TEXTY+row,2,mBuf);
row += 10;
}
/* Debug line to show how much memory the system has left */
sprintf(mBuf,"Memory.........%dK",farcoreleft()/1024L);
smWriteHUD(VP_TEXTX,VP_TEXTY+row,2,mBuf);
}
/****************************************************************************
** Displays the contents of the specified text file onto the viewport **
** window. **
** **
****************************************************************************/
void ShowTextFile(char *fName)
{
int x,y;
char buf[80];
FILE *fp;
fp = fopen(fName,"rt");
if (fp == NULL)
return;
x = VP_TEXTX;
y = VP_TEXTY;
mouse_hide_cursor();
ShowColor(7);
while (1)
{
if (feof(fp))
break;
*buf = '\0';
fgets(buf,78,fp);
y = smWriteString(x,y,buf);
}
mouse_show_cursor();
fclose(fp);
}
/****************************************************************************
** Changes the shape of the mouse cursor when in UW2 mode. **
** **
****************************************************************************/
void SetMouseCursor(int index)
{
mouse_set_graphics_cursor(mCursors[index].hy,
mCursors[index].hx,
(UCHAR far *)mCursors[index].Cursor);
}
/****************************************************************************
** Keyboard interrupt 9 **
****************************************************************************/
void interrupt myInt(void)
{
register char x;
scanCode = inp(0x60); // read keyboard data port
x = inp(0x61);
outp(0x61, (x | 0x80));
outp(0x61, x);
outp(0x20, 0x20);
Keys[scanCode & 127] = 1;
if (scanCode & 128)
Keys[scanCode & 127] = 0;
}
/****************************************************************************
** Our timer countdown routine. For game time we are counting down faster **
** than real time (adds to the suspense?). **
** **
****************************************************************************/
void interrupt MyTimer(void)
{
tmCounter++;
if (tmSeconds == 0 &&
tmMinutes == 0 &&
tmHours == 0)
return;
tmDelay--;
if (!tmDelay)
{
tmDelay = TIME_DELAY;
tmSeconds--;
if (tmSeconds < 0)
{
tmSeconds = 59;
tmMinutes--;
if (tmMinutes < 0)
{
if (tmHours)
{
tmHours--;
tmMinutes = 59;
}
else
tmMinutes = tmSeconds = 0;
}
}
}
}
/****************************************************************************
** Routine currently not used. This allows the Wolf style mouse actions **
** It is called once during InitializeMouse() **
****************************************************************************/
void CheckMouse(MOUSE *m)
{
int dx,dy;
int x,y,buttons;
if (HaveMouse)
{
mouse_read_cursor(&buttons,&y,&x);
dx = x - 160;
dy = y - 120;
m->mButtons = buttons;
mouse_set_cursor(120,160);
if (abs(dy) > 10 && abs(dx) < 32)
dx >>= 2;
m->mdx = dx;
m->mdy = dy;
}
}
/****************************************************************************
** Determines if the mouse is present. **
** **
****************************************************************************/
int InitializeMouse(void)
{
memset(&mouse,0,sizeof(MOUSE));
HaveMouse = 0;
if (mouse_installed() == -1)
{
HaveMouse = 1;
CheckMouse(&mouse);
}
return(HaveMouse);
}
/****************************************************************************
** This routine simply runs through the video and replaces any old colors **
** with a new color. Good for special effects when text is being displayed **
** **
****************************************************************************/
void ReplaceColor(UCHAR OldColor,UCHAR NewColor)
{
int rows,cols;
UCHAR far *Video;
Video = MK_FP(0xA000,VIDEO_OFFSET);
for (rows = 0; rows < VIDEO_ROWS; rows++)
{
for (cols = 0; cols < VIDEO_COLS; cols++)
{
if (Video[cols] == OldColor)
Video[cols] = NewColor;
}
Video += 320;
}
}
/****************************************************************************
** Essentially a clear screen buffer to the specified color. Allows setting**
** the background color that appears in the viewport window when text is **
** being displayed. **
****************************************************************************/
void ShowColor(UCHAR color)
{
memset(ae->ScreenBuffer,color,64000);
AckDrawOverlay(ae->ScreenBuffer,ae->OverlayBuffer);
AckDisplayScreen(ae);
}
/* This is actually in the ACK engine lib */
extern UINT far *Grid;
/****************************************************************************
** Displays an overhead map of the entire station. This routine relies on **
** external variables in the ACK engine and is kind of a cheat from the **
** proper way of keeping the application isolated from the engine. **
** **
****************************************************************************/
void ShowOverhead(void)
{
int row,col,mPos,offset;
int MidRow,MidCol,MidOffset;
int mx,my,mbuttons,gCode;
UCHAR Color;
UCHAR far *Video;
mouse_hide_cursor();
ShowColor(7);
mx = VP_STARTX + (((VP_ENDX - VP_STARTX) - 128) / 2);
my = VP_STARTY + (((VP_ENDY - VP_STARTY) - 64) / 2);
Video = MK_FP(0xA000,(my * 320) + mx);
MidRow = ae->yPlayer >> 6;
MidCol = ae->xPlayer >> 6;
for (row = 0; row < GRID_HEIGHT; row++)
{
offset = 0;
for (col = 0; col < GRID_WIDTH; col++)
{
mPos = (row << 6) + col;
gCode = Grid[mPos];
switch (gCode & 0xFF)
{
case 0:
Color = 0;
break;
case DOOR_XCODE:
case DOOR_YCODE:
Color = 9;
break;
default:
Color = 15;
if (gCode & 0x80)
Color = 12;
break;
}
if (gCode & DOOR_TYPE_SECRET)
Color = 11;
if (row == MidRow && col == MidCol)
{
Color = 12;
MidOffset = FP_OFF(Video) + offset;
}
Video[offset] = Color;
Video[offset+1] = Color;
offset += 2;
}
Video += 320;
}
Video = MK_FP(0xA000,MidOffset);
mouse_show_cursor();
mouse_released();
mPos = 0;
row = 500;
while (1)
{
mouse_read_cursor(&mbuttons,&my,&mx);
if (mbuttons & 1)
break;
if (Keys[ENTER_KEY])
break;
row--;
if (!row)
{
Video[0] = mPos;
Video[1] = mPos;
mPos ^= 12;
if (mPos)
row = 100;
else
row = 500;
}
}
mouse_released();
}
/****************************************************************************
** Pauses here until mouse button is released **
****************************************************************************/
void mouse_released(void)
{
int mbutton,mx,my;
mouse_read_cursor(&mbutton,&my,&mx);
while (mbutton)
mouse_read_cursor(&mbutton,&my,&mx);
}
/****************************************************************************
** Checks the location of the mouse to see if the mouse cursor needs to **
** change shape (used in UW2 mode). **
** **
****************************************************************************/
void CheckMouseCursor(int x,int y)
{
int index;
index = 0;
if (y >= VP_STARTY && y <= VP_ENDY && x >= VP_STARTX && x <= VP_ENDX)
{
if (x < VP_LARROWX)
index = MOUSE_LTARROW;
if (x > VP_RARROWX)
index = MOUSE_RTARROW;
if (x >= VP_LARROWX && x <= VP_RARROWX)
{
if (y < VP_UDARROWY)
index = MOUSE_UPARROW;
else
index = MOUSE_DNARROW;
}
}
if (index != LastMouseIndex)
{
SetMouseCursor(index);
LastMouseIndex = index;
}
}
/****************************************************************************
** Update all the walls as needed. **
****************************************************************************/
void AnimateWalls(void)
{
int i;
ae->bMaps[WallType[0]] = wMaps[WallIndex];
WallIndex++;
if (WallIndex > 2)
WallIndex = 0;
WallDelay--;
if (WallDelay)
return;
WallDelay = WALL_DELAY;
ae->bMaps[WallType1[0]] = wMaps1[WallIndex1];
WallIndex1++;
if (WallIndex1 > 3)
WallIndex1 = 0;
ae->bMaps[WallType2[0]] = wMaps2[WallIndex2];
WallIndex2++;
if (WallIndex2 > 1)
WallIndex2 = 0;
ae->bMaps[WallType3[0]] = wMaps3[WallIndex3];
WallIndex3++;
if (WallIndex3 > 1)
WallIndex3 = 0;
ae->bMaps[WallType4[0]] = wMaps4[WallIndex4];
WallIndex4++;
if (WallIndex4 > 1)
WallIndex4 = 0;
}
/****************************************************************************
** Setup pointers to animated wall bitmaps **
****************************************************************************/
void SetupAnimatedWalls(void)
{
int i;
for (i = 0; i < 3; i++)
wMaps[i] = ae->bMaps[WallType[i]];
for (i = 0; i < 4; i++)
wMaps1[i] = ae->bMaps[WallType1[i]];
for (i = 0; i < 2; i++)
wMaps2[i] = ae->bMaps[WallType2[i]];
for (i = 0; i < 2; i++)
wMaps3[i] = ae->bMaps[WallType3[i]];
for (i = 0; i < 2; i++)
wMaps4[i] = ae->bMaps[WallType4[i]];
for (i = 0; i < 4; i++)
hMaps[i] = ae->bMaps[HoloWalls[i]];
WallIndex = 1;
WallIndex1 = 1;
WallIndex2 = 1;
WallIndex3 = 1;
WallIndex4 = 1;
HoloIndex = 0;
}
/****************************************************************************
** Display the time remaining to the player. **
****************************************************************************/
void ShowTime(void)
{
char buf[48];
sprintf(buf,"Time remaining: %02d:%02d:%02d",tmHours,tmMinutes,tmSeconds);
smWriteString(VP_TIMEX,VP_TIMEY,buf);
}
/****************************************************************************
** Clears the statusline section at the bottom of the screen to the color **
** specified. **
** **
****************************************************************************/
void ClearStatusLine(UCHAR color)
{
int rows,cols;
UCHAR far *Video;
rows = (VP_STATUSY * 320) + VP_STATUSX;
Video = MK_FP(0xA000,rows);
cols = (VP_STATUSX1 - VP_STATUSX) + 1;
for (rows = VP_STATUSY; rows < VP_STATUSY1; rows++)
{
memset(Video,color,cols);
Video += 320;
}
}
/****************************************************************************
** Displays the energy bar underneath the viewport. **
** **
****************************************************************************/
void ShowLightbar(void)
{
int row,col1,col2;
UCHAR far *Video;
Video = MK_FP(0xA000,VP_LIGHTBAR_OFFSET);
if (BoltEnergy < 0)
BoltEnergy = 0;
col1 = BoltEnergy * 2;
if (col1 >= VP_LIGHTBAR_COLS)
col1 = VP_LIGHTBAR_COLS - 1;
col2 = (VP_LIGHTBAR_COLS - col1) - 1;
if (col2)
col2++;
else
col1++;
for (row = 0; row < VP_LIGHTBAR_ROWS; row++)
{
if (col1)
memset(Video,2,col1);
if (col2)
memset(&Video[col1],4,col2);
Video += 320;
}
}
/****************************************************************************
** Makes a call into the library to play the specified sound effect. **
** **
****************************************************************************/
void AppPlaySound(int VocIndex)
{
#if USE_SOUND
AckPlaySound(VocIndex);
#else
VocIndex--; /* Keep compiler happy */
#endif
}
/****************************************************************************
** Check for objects hit and take the appropriate action. This routine is **
** called when the player moves and strikes something. **
****************************************************************************/
void CheckOurObjects(void)
{
int i;
i = AckGetObjectHit(); /* Get index to object */
switch(i)
{
case 1:
case 2:
case 29:
AppPlaySound(SOUND_HITBADOBJECT);
if (BoltEnergy)
BoltEnergy--;
ShowLightbar();
break;
case 10:
case 39:
AppPlaySound(SOUND_HITOBJECT);
BoltEnergy += 30;
if (BoltEnergy > 77) BoltEnergy = 77;
ShowLightbar();
AckDeleteObject(ae,i);
break;
case 8:
case 9:
case 25:
case 27:
AppPlaySound(SOUND_HITOBJECT);
if (i == 25 && ObjectList[OBJ_COMPUTER] == 2)
break;
if (i == 27 && ObjectList[OBJ_FUELCELLS] == 2)
break;
if (TotalInventory < MAX_INVENTORY)
{
AckDeleteObject(ae,i);
Inventory[TotalInventory++] = i;
if (i == 25)
ObjectList[OBJ_COMPUTER] = 1;
if (i == 27)
ObjectList[OBJ_FUELCELLS] = 1;
}
break;
case 26:
AppPlaySound(SOUND_HITOBJECT);
if (ObjectList[OBJ_CIRCUITBOARD] == 2)
break;
if (TotalInventory < MAX_INVENTORY)
{
AckDeleteObject(ae,26);
UnlockDoors();
Inventory[TotalInventory++]= 26;
ObjectList[OBJ_CIRCUITBOARD] = 1;
}
break;
default:
if (i < 50)
AppPlaySound(SOUND_HITOBJECT);
break;
}
}
/****************************************************************************
** This routine will unlock ALL doors in the map **
****************************************************************************/
void UnlockDoors(void)
{
int i;
for (i = 0; i < GRID_MAX; i++)
{
if (ae->xGrid[i] & DOOR_LOCKED)
ae->xGrid[i] &= ~DOOR_LOCKED;
if (ae->yGrid[i] & DOOR_LOCKED)
ae->yGrid[i] &= ~DOOR_LOCKED;
}
}
/****************************************************************************
** Check for doors opening or closing and play the appropriate sound. **
** **
****************************************************************************/
void PlayDoorSounds(void)
{
int i,DoorColumn;
for (i = 0; i < MAX_DOORS; i++)
{
if (ae->Door[i].ColOffset)
{
DoorColumn = 64;
if (ae->Door[i].mCode & DOOR_TYPE_SPLIT)
DoorColumn = 32;
if (ae->Door[i].ColOffset < DoorColumn)
{
if (ae->Door[i].Flags & DOOR_OPENING)
{
AppPlaySound(SOUND_DOOROPENING);
ae->Door[i].Flags &= ~DOOR_OPENING;
}
if (ae->Door[i].Flags & DOOR_CLOSING)
{
AppPlaySound(SOUND_DOORCLOSING);
ae->Door[i].Flags &= ~DOOR_CLOSING;
}
}
}
}
}
/****************************************************************************
** Move the energy bolt and check for collision with walls or objects. **
** If a wall is hit then display damage, if a porthole is hit then the **
** station decompresses and the player loses. **
** **
****************************************************************************/
void UpdateBomb(void)
{
int oNum,j,wCode,bCode,NewCode;
int hFlag;
oNum = MAX_OBJECTS-1;
wCode = 0;
hFlag = 0;
j = AckMoveObjectPOV(ae,oNum,ae->ObjList[oNum].Dir,ae->ObjList[oNum].Speed);
if (j != POV_NOTHING && j != POV_PLAYER)
{
ae->ObjList[oNum].Active = 0;
Shooting = 0;
oNum = AckGetWallHit();
if (j == POV_XWALL)
{
AppPlaySound(SOUND_EXPLODE);
wCode = ae->xGrid[oNum] & 0xFF;
bCode = wCode & 0x3F;
if (bCode == 25)
ae->ObjList[MAX_OBJECTS-2].Active = 0;
if (bCode >= WallType1[0] && bCode <= WallType1[3])
Decompress = 1;
if (bCode > 21 && bCode < 25)
Decompress = 1;
if (bCode == HoloWalls[0] || bCode == HoloWalls[1])
hFlag = 1;
if (bCode < DOOR_XCODE && !hFlag)
{
bCode = wCode | 0x80;
NewCode = 57;
if (wCode == bCode)
{
bCode |= 0xC0;
NewCode = 56;
}
if (ae->bMaps[bCode] == NULL)
{
ae->bMaps[bCode] = AckCopyNewBitmap(ae->bMaps[wCode]);
if (ae->bMaps[bCode] != NULL)
AckOverlayBitmap(ae->bMaps[bCode],ae->bMaps[NewCode]);
}
if (ae->bMaps[bCode] != NULL)
ae->xGrid[oNum] = bCode;
}
}
if (j == POV_YWALL)
{
AppPlaySound(SOUND_EXPLODE);
wCode = ae->yGrid[oNum] & 0xFF;
bCode = wCode & 0x3F;
if (bCode == 25)
ae->ObjList[MAX_OBJECTS-2].Active = 0;
if (bCode >= WallType1[0] && bCode <= WallType1[3])
Decompress = 1;
if (bCode == HoloWalls[0] || bCode == HoloWalls[1])
hFlag = 1;
if (bCode < DOOR_XCODE && !hFlag)
{
bCode = wCode | 0x80;
NewCode = 57;
if (wCode == bCode)
{
bCode |= 0xC0;
NewCode = 56;
}
if (ae->bMaps[bCode] == NULL)
{
ae->bMaps[bCode] = AckCopyNewBitmap(ae->bMaps[wCode]);
if (ae->bMaps[bCode] != NULL)
AckOverlayBitmap(ae->bMaps[bCode],ae->bMaps[NewCode]);
}
if (ae->bMaps[bCode] != NULL)
ae->yGrid[oNum] = bCode;
}
}
if (j == POV_OBJECT)
{
oNum = AckGetObjectHit();
if (oNum >= 50 && oNum < 70)
{
if (ae->ObjList[oNum].Flags & OF_ANIMATE)
{
AppPlaySound(SOUND_USER2);
AckDeleteObject(ae,oNum+20);
ae->ObjList[oNum].Flags &= ~OF_ANIMATE;
ae->ObjList[oNum].Flags |= OF_PASSABLE;
ae->ObjList[oNum].CurNum = 0;
ae->ObjList[oNum].MaxNum = 0;
ae->ObjList[oNum].bmNum[0] = 51;
ae->ObjList[oNum].Speed = 1;
}
else
Shooting = 1;
}
}
}
else
{
ae->ObjList[oNum].CurNum++;
if (ae->ObjList[oNum].CurNum >= ae->ObjList[oNum].MaxNum)
ae->ObjList[oNum].CurNum = 0;
}
if (wCode)
{
wCode &= 0x3F;
if (wCode == 36)
{
smWriteString(180,VP_TIMEY," You are so cruel! ");
}
if (hFlag && HoloIndex < 2)
{
HoloIndex = 2;
smWriteString(180,VP_TIMEY,"Holodeck program terminated.");
ae->bMaps[HoloWalls[0]] = hMaps[HoloIndex];
ae->ObjList[3].Active = 0;
ae->ObjList[4].Active = 0;
ae->ObjList[9].Active = 0;
ae->ObjList[11].Active = 0;
}
}
}
/****************************************************************************
** This is one example of moving a very specific object around in the map. **
** In this case the bolt of energy in the plasma lab is shot out of one **
** wall, moves across the room until striking the other wall and then **
** starts over. **
****************************************************************************/
void UpdateWallBolt(void)
{
int oNum,j,wCode;
oNum = MAX_OBJECTS-2;
if (!ae->ObjList[oNum].Active)
return;
j = AckMoveObjectPOV(ae,oNum,ae->ObjList[oNum].Dir,ae->ObjList[oNum].Speed);
if (j != POV_NOTHING)
{
if (j == POV_PLAYER)
{
AppPlaySound(SOUND_HITBADOBJECT);
mouse_hide_cursor();
ShowColor(4);
if (BoltEnergy)
{
BoltEnergy--;
ShowLightbar();
}
mouse_show_cursor();
}
ae->ObjList[oNum].x = 1184;
ae->ObjList[oNum].y = 2976;
}
else
{
ae->ObjList[oNum].CurNum++;
if (ae->ObjList[oNum].CurNum >= ae->ObjList[oNum].MaxNum)
ae->ObjList[oNum].CurNum = 0;
}
}
/****************************************************************************
** This routine updates all the spacemen in the station, first by changing **
** the bitmap that is displayed and second, by updating any plasma bolts **
** they may have fired. Note that all the work is done here and the ACK **
** engine is only called to actually move the objects. The result of the **
** movement is then checked to see if the player was hit or not. **
** **
****************************************************************************/
void UpdateSpaceMen(void)
{
int i,j,x,y,px,py,oNum,angle,oHit;
int dx,dy,x1,y1;
x1 = px = ae->xPlayer;
y1 = py = ae->yPlayer;
for (i = 50; i < 70; i++)
{
if (!ae->ObjList[i].Active || !(ae->ObjList[i].Flags & OF_ANIMATE))
{
if (ae->ObjList[i].bmNum[0] > 48)
{
if (ae->ObjList[i].Speed-- <= 0)
{
ae->ObjList[i].bmNum[0]--;
ae->ObjList[i].Speed = 1;
}
}
continue;
}
oNum = i + 20;
if (!ae->ObjList[oNum].Active)
{
if (SpaceMenDelay[i-50] > tmCounter)
continue;
x = ae->ObjList[i].x;
y = ae->ObjList[i].y;
px = x1;
py = y1;
dx = abs(px - x);
dy = abs(py - y);
if (dx > dy)
py = y;
if (dx < dy)
px = x;
if (py == y)
{
if (px < x) angle = INT_ANGLE_180;
if (px > x) angle = 0;
}
if (px == x)
{
if (py < y) angle = INT_ANGLE_270;
if (py > y) angle = INT_ANGLE_90;
}
ae->ObjList[oNum].Active = 1;
ae->ObjList[oNum].x = x;
ae->ObjList[oNum].y = y;
ae->ObjList[oNum].Dir = angle;
}
j = AckMoveObjectPOV(ae,oNum,ae->ObjList[oNum].Dir,ae->ObjList[oNum].Speed);
if (j != POV_NOTHING)
{
oHit = AckGetObjectHit();
if (oHit == i)
j = POV_NOTHING;
}
if (j != POV_NOTHING)
{
if (j == POV_PLAYER)
{
AppPlaySound(SOUND_HITBADOBJECT);
mouse_hide_cursor();
ShowColor(4);
if (BoltEnergy)
{
BoltEnergy -= 3;
if (BoltEnergy < 0)
BoltEnergy = 0;
ShowLightbar();
}
mouse_show_cursor();
}
ae->ObjList[oNum].Active = 0;
SpaceMenDelay[i-50] = tmCounter + random(30);
}
else
{
ae->ObjList[oNum].CurNum++;
if (ae->ObjList[oNum].CurNum >= ae->ObjList[oNum].MaxNum)
ae->ObjList[oNum].CurNum = 0;
}
}
}
/****************************************************************************
** Display the instruction text and wait for the ENTER key to be pressed. **
****************************************************************************/
void ShowInstructions(void)
{
int mx,my,mbuttons;
FontColor = 0;
TextBGcolor = 7;
mouse_hide_cursor();
ShowTextFile("instr.txt");
mouse_show_cursor();
mouse_released();
FontColor = 15;
while (!Keys[ENTER_KEY])
{
mouse_read_cursor(&mbuttons,&my,&mx);
if (mbuttons)
break;
}
}
extern UCHAR far colordat[];
/****************************************************************************
** Displays the rotating compass under the viewport depending on what **
** direction the player is facing. **
****************************************************************************/
void ShowCompass(void)
{
int x,wt;
UCHAR far *Src,*sBuf;
sBuf = ae->ScreenBuffer + 45896;
wt = (*(int *)CompassBmp);
x = ae->PlayerAngle / 8;
x -= 17;
if (x < 0)
x += 240;
Src = CompassBmp + x + 4;
for (x = 0; x < 7; x++)
{
memmove(sBuf,Src,49);
sBuf += 320;
Src += wt;
}
}
/****************************************************************************
** Quicky routine to display the specified bitmap on the video. Used to **
** show the objects being carried so they can be dropped. **
** **
****************************************************************************/
void ShowBitmap(int x,int y,UCHAR far *Bmp)
{
int row,col;
UCHAR far *Video;
UCHAR far *vPtr;
Video = MK_FP(0xA000,(y * 320) + x);
for (col = 0; col < 64; col++)
{
vPtr = Video;
for (row = 0; row < 64; row++)
{
*vPtr = *Bmp++;
vPtr += 320;
}
Video++;
}
}
/****************************************************************************
** Clears the screen and shows the objects currently carried by the player.**
** Note that the ACK engine must be called to get a pointer to the bitmap **
** since it could be in XMS memory. **
****************************************************************************/
void ShowInventoryObjects(void)
{
int i,x,y;
UCHAR far *Video;
UCHAR far *Bmp;
Video = MK_FP(0xA000,0);
mouse_hide_cursor();
memmove(ae->ScreenBuffer,Video,64000);
memset(Video,0,64000);
x = y = 0;
for (i = 0; i < TotalInventory; i++)
{
Bmp = AckGetBitmapPtr(ae->ObjList[Inventory[i]].bmNum[0],ae->oMaps);
ShowBitmap(x,y,Bmp);
x += 64;
if (x > 256)
{
y += 64;
x = 0;
}
}
Video = MK_FP(0xA000,57600U);
memset(Video,7,6400);
smWriteString(30,190,"Select object");
mouse_show_cursor();
}
/****************************************************************************
** Shows the objects the player is carrying and then allows the player to **
** select an object to drop. When dropped the object has the current player**
** location. A check is then made to see if all the required objects have **
** been dropped in the proper location to win the game. **
****************************************************************************/
void DropObject(void)
{
int done,oNum,iPos,mx,my,mbutton;
int px,py;
UCHAR far *Video;
if (!TotalInventory)
return;
ShowInventoryObjects();
if (MouseMode)
mouse_show_cursor();
px = ae->xPlayer >> 6;
py = ae->yPlayer >> 6;
done = 0;
while (!done)
{
mouse_read_cursor(&mbutton,&my,&mx);
if (mbutton & 2 || Keys[ENTER_KEY])
break;
if (mbutton & 1)
{
my >>= 6;
mx >>= 6;
iPos = (my * 4) + mx;
if (iPos < TotalInventory)
{
oNum = Inventory[iPos];
ae->ObjList[oNum].Active = 1;
ae->ObjList[oNum].x = ae->xPlayer;
ae->ObjList[oNum].y = ae->yPlayer;
mx = MAX_INVENTORY - iPos;
memmove(&Inventory[iPos],&Inventory[iPos+1],mx);
TotalInventory--;
switch (oNum)
{
case 25:
ObjectList[OBJ_COMPUTER] = 0;
if (px > 40 && px < 46 && py > 48 && py < 53)
ObjectList[OBJ_COMPUTER] = 2;
break;
case 26:
ObjectList[OBJ_CIRCUITBOARD] = 0;
if (px > 40 && px < 46 && py > 48 && py < 53)
ObjectList[OBJ_CIRCUITBOARD] = 2;
break;
case 27:
ObjectList[OBJ_FUELCELLS] = 0;
if (px > 40 && px < 46 && py > 48 && py < 53)
ObjectList[OBJ_FUELCELLS] = 2;
break;
default:
break;
}
break;
}
}
}
mouse_released();
Video = MK_FP(0xA000,0);
mouse_hide_cursor();
memmove(Video,ae->ScreenBuffer,64000);
if (!MouseMode)
mouse_show_cursor();
for (mx = 0; mx < 3; mx++)
{
if (ObjectList[mx] != 2)
return;
}
YouWON = 1;
}
/****************************************************************************
** This routine copies a DP2 brush file on top of the screen for later **
** display. Used in the title sequence to move the words over the station. **
** **
****************************************************************************/
void OverlayBrush(int x,int y,UCHAR far *Screen,UCHAR far *Brush)
{
int wt,ht,col;
UINT offset;
UCHAR ch;
wt = (*(int *)Brush);
Brush += 2;
ht = (*(int *)Brush);
Brush += 2;
if (y >= 0)
offset = (y * 320) + x;
else
offset = x;
Screen += offset;
for (;ht > 0; ht--)
{
if (y >= 0 && y < 199)
{
for (col = 0; col < wt; col++)
{
ch = *Brush++;
if (ch)
Screen[col] = ch;
}
Screen += 320;
}
else
Brush += wt;
if (++y > 199)
break;
}
}
/****************************************************************************
** Displays the space station title. **
** **
****************************************************************************/
void ShowTitle(void)
{
int sx,sy,ex,ey,ax,ay,len;
int kFlag;
UINT offset;
UCHAR far *Video;
UCHAR far *Screen;
UCHAR far *tBuf;
UCHAR far *sBuf;
UCHAR far *eBuf;
UCHAR far *aBuf;
kFlag = 0;
Video = MK_FP(0xA000,0);
Screen = malloc(64000);
if (Screen == NULL)
return;
tBuf = AckReadiff("bitmaps\\stat01.lbm");
if (tBuf != NULL)
{
memmove(tBuf,&tBuf[4],64000);
memmove(Video,tBuf,64000);
AckFadeIn(0,255,colordat);
}
sBuf = AckReadiff("bitmaps\\station.bbm");
eBuf = AckReadiff("bitmaps\\escape.bbm");
aBuf = AckReadiff("bitmaps\\ack3d.bbm");
offset = 76 * 320;
len = 64000 - offset;
if (sBuf != NULL &&
eBuf != NULL &&
aBuf != NULL)
{
sx = 3;
sy = -80;
ex = 17;
ey = 210;
ax = 60;
ay = 210;
while (sy < 10)
{
memmove(Screen,tBuf,64000);
OverlayBrush(sx,sy,Screen,sBuf);
memmove(Video,Screen,len);
sy++;
if (kbhit())
{
kFlag = 1;
getch();
sy = 10;
ey = 76;
ay = 130;
}
}
OverlayBrush(sx,sy,tBuf,sBuf);
while (ey > 76)
{
memmove(Screen,tBuf,64000);
OverlayBrush(ex,ey,Screen,eBuf);
memmove(&Video[offset],&Screen[offset],len);
ey--;
if (kbhit())
{
kFlag = 1;
getch();
ey = 76;
ay = 130;
}
}
OverlayBrush(ex,ey,tBuf,eBuf);
while (ay > 130)
{
memmove(Screen,tBuf,64000);
OverlayBrush(ax,ay,Screen,aBuf);
memmove(&Video[offset],&Screen[offset],len);
ay--;
if (kbhit())
{
kFlag = 1;
getch();
ay = 130;
}
}
}
if (Screen != NULL)
free(Screen);
if (tBuf != NULL)
free(tBuf);
if (sBuf != NULL)
free(sBuf);
if (eBuf != NULL)
free(eBuf);
if (aBuf != NULL)
free(aBuf);
if (!kFlag)
{
tBuf = AckReadiff("bitmaps\\credits.lbm");
if (tBuf != NULL)
{
AckFadeOut(0,255);
memmove(Video,&tBuf[4],64000);
memset(tBuf,0,768);
AckSetPalette(tBuf);
AckFadeIn(0,255,colordat);
ex = 500;
while (ex--)
{
if (kbhit())
{
getch();
break;
}
delay(10);
}
free(tBuf);
}
}
}
/****************************************************************************
** Checks the map location of the player for special things, in this case **
** to see if the player is about ready to enter the holodeck. **
** **
****************************************************************************/
void CheckPlayerSquare(void)
{
int row,col,mPos,hProg,aFlag;
row = ae->yPlayer >> 6;
col = ae->xPlayer >> 6;
mPos = (row << 6) + col;
aFlag = 0;
if (!HoloSoundFlag &&
col == 11 &&
ae->PlayerAngle > INT_ANGLE_180 &&
row == 33)
{
hProg = PickHoloProgram();
switch (hProg)
{
case -1:
return;
case 0:
HoloIndex = 2;
break;
case 1:
aFlag = 1;
HoloIndex = 0;
break;
case 2:
HoloIndex = 1;
break;
default:
break;
}
ae->ObjList[3].Active = aFlag;
ae->ObjList[4].Active = aFlag;
ae->ObjList[9].Active = aFlag;
ae->ObjList[11].Active = aFlag;
ae->bMaps[HoloWalls[0]] = hMaps[HoloIndex];
HoloSoundFlag = 1;
AppPlaySound(SOUND_USER1);
return;
}
if (col != 11 || row != 33)
HoloSoundFlag = 0;
}
/****************************************************************************
** Our main entry point. There is alot of stuff here that should be **
** broken out into separate routines. My apologies for the mess! **
** **
****************************************************************************/
int main(int argc,char *argv[])
{
int i,j,result,done;
int ViewNum,count;
int Spin,SpinAngle;
int mx,my,mbuttons;
int LostFlag,SkipTitle;
int NoMusic,MusicFlag;
char LastSeconds;
UCHAR far *oBuf;
UCHAR far *Video;
UCHAR OldColor,NewColor;
if (!InitializeMouse())
{
printf("Mouse required to run.\n");
return(1);
}
/* Disabled for now, should be in final version to not run if memory low */
#if 0
mx = (int)(farcoreleft() / 1024L);
if (mx < 450)
{
printf("Not enough memory to run. Current memory: %d\n",mx);
return(1);
}
#endif
/*------------------------------------------------------------------------*/
/* Get the memory for the interface structure. This can either be GLOBAL */
/* or allocated. */
/*------------------------------------------------------------------------*/
ae = malloc(sizeof(ACKENG));
if (ae == NULL)
{
printf("Not enough memory to run.\n");
return(1);
}
memset(ae,0,sizeof(ACKENG));
if (LoadSmallFont())
{
printf("Not enough memory to run.\n");
return(1);
}
YouWON = 0;
BoltEnergy = 77;
Shooting = 0;
LostFlag = 0;
ViewNum = 0;
SoundDevice = DEV_SOUNDBLASTER;
MouseMode = 0;
SkipTitle = 0;
NoMusic = 0;
HoloSoundFlag = 0;
TextBGcolor = 7;
randomize();
MusicFlag = 1;
if (argc > 1)
{
for (i = 1; i < argc; i++)
{
if (!stricmp(argv[i],"-NS"))
SoundDevice = DEV_NOSOUND;
if (!stricmp(argv[i],"-M1"))
MouseMode = 1;
if (!stricmp(argv[i],"-SP"))
SoundDevice = DEV_PCSPEAKER;
if (!stricmp(argv[i],"-ST"))
SkipTitle = 1;
if (!stricmp(argv[i],"-NM"))
NoMusic = 1;
}
}
AckSetVGAmode();
memset(colordat,0,768);
AckSetPalette(colordat);
if (!SkipTitle)
ShowTitle();
#if USE_SOUND
if (AckSoundInitialize(SoundDevice))
{
AckSetTextmode();
printf("Error initializing sound.\n");
return(1);
}
#endif
WallDelay = WALL_DELAY;
tmHours = START_HOURS;
tmMinutes = START_MINUTES;
LastSeconds = tmSeconds = START_SECONDS;
tmDelay = TIME_DELAY;
/*------------------------------------------------------------------------*/
/* Setup the structure for this particular application. The most important*/
/* fields before initializing are the viewport (or Win...) fields. */
/*------------------------------------------------------------------------*/
ae->WinStartY = VP_STARTY;
ae->WinEndY = VP_ENDY;
ae->WinStartX = VP_STARTX;
ae->WinEndX = VP_ENDX;
ae->LightFlag = SHADING_ON;
ae->xPlayer = Views[ViewNum].xP;
ae->yPlayer = Views[ViewNum].yP;
ae->PlayerAngle = Views[ViewNum].Angle;
ae->TopColor = 28;
ae->BottomColor = 28;
ae->DoorSpeed = 4;
ae->NonSecretCode = 1;
strcpy(GridFile,"demomap.l01");
result = AckInitialize(ae);
if (result)
{
AckSetTextmode();
printf("Initialize Error: %d\n",result);
#if USE_SOUND
AckSoundShutdown();
#endif
return(1);
}
if (ReadMasterFile("demo.l01"))
{
AckSetTextmode();
printf("Error reading ASCII file - ErrorCode = %d\n",ErrorCode);
AckWrapUp(ae);
#if USE_SOUND
AckSoundShutdown();
#endif
return(1);
}
result = AckReadMapFile(ae,GridFile);
if (result)
{
AckSetTextmode();
printf("Error reading map file - ErrorCode = %d\n",result);
AckWrapUp(ae);
#if USE_SOUND
AckSoundShutdown();
#endif
return(1);
}
i = ae->MaxObjects;
nums[0] = 24;
nums[1] = 25;
nums[2] = 26;
nums[3] = 27;
ae->ObjList[MAX_OBJECTS-1].Dir = 10;
ae->ObjList[MAX_OBJECTS-1].Speed = 44;
AckCreateObject(ae,MAX_OBJECTS-1,4,nums);
ae->ObjList[MAX_OBJECTS-2].Dir = 10;
ae->ObjList[MAX_OBJECTS-2].Speed = 34;
AckCreateObject(ae,MAX_OBJECTS-2,4,nums);
ae->ObjList[MAX_OBJECTS-2].Dir = INT_ANGLE_270;
ae->ObjList[MAX_OBJECTS-2].x = 1184;
ae->ObjList[MAX_OBJECTS-2].y = 2976;
ae->ObjList[MAX_OBJECTS-2].Active = 1;
ae->MaxObjects = i;
ae->ObjList[35].Active = 0;
ae->ObjList[36].Active = 0;
ae->ObjList[37].Active = 0;
if (ae->BkgdBuffer)
free(ae->BkgdBuffer);
ae->BkgdBuffer = AckReadiff("bitmaps\\back1.lbm");
if (ae->BkgdBuffer == NULL)
{
AckSetTextmode();
printf("Not enough memory to load background.\n");
AckWrapUp(ae);
#if USE_SOUND
AckSoundShutdown();
#endif
return(1);
}
CompassBmp = AckReadiff("bitmaps\\compass.bbm");
if (CompassBmp == NULL)
{
AckSetTextmode();
printf("Not enough memory to run.\n");
AckWrapUp(ae);
#if USE_SOUND
AckSoundShutdown();
#endif
return(1);
}
/*------------------------------------------------------------------------*/
/* Load our main screen which can also be used as an overlay */
/*------------------------------------------------------------------------*/
oBuf = AckReadiff("bitmaps\\demo5.lbm");
if (oBuf == NULL)
{
AckSetTextmode();
printf("Not enough memory to load overlay.\n");
AckWrapUp(ae);
#if USE_SOUND
AckSoundShutdown();
#endif
return(1);
}
#if USE_SOUND
for (i = 0; i < SOUND_MAX_INDEX; i++)
{
if (SoundFiles[i] != NULL)
AckLoadSound(i,SoundFiles[i]);
}
if (!NoMusic)
AckPlayBackground(MusicFile);
else
MusicFlag = 0;
#endif
SetupAnimatedWalls();
Video = MK_FP(0xA000,0);
if (!SkipTitle)
{
AckFadeOut(0,255);
memset(Video,0,64000);
memset(ae->ScreenBuffer,0,768);
AckSetPalette(ae->ScreenBuffer);
}
AckLoadAndSetPalette(PalFile);
memset(ae->ScreenBuffer,0,768);
AckSetPalette(ae->ScreenBuffer);
/*------------------------------------------------------------------------*/
/* Just blit the main screen to the video (then fade later) */
/*------------------------------------------------------------------------*/
memmove(Video,&oBuf[4],64000);
AckCreateOverlay(ae,&oBuf[4]);
ClearStatusLine(7);
ShowTime();
ShowLightbar();
if (!SkipTitle)
ShowTextFile("intro.txt");
AckFadeIn(0,255,colordat);
if (!SkipTitle)
{
mbuttons = 0;
while (!mbuttons)
{
mouse_read_cursor(&mbuttons,&my,&mx);
if (kbhit())
{
getch();
break;
}
}
}
oldvec=getvect(KEYBD);
setvect(KEYBD,myInt);
OldTimer = getvect(0x1C);
setvect(0x1C,MyTimer);
/*------------------------------------------------------------------------*/
/* Use our main screen to create an overlay (we don't use it but this */
/* is how an application would call the ACK engine) */
/*------------------------------------------------------------------------*/
if (!MouseMode)
mouse_show_cursor();
LastMouseIndex = MOUSE_ARROW;
SetMouseCursor(LastMouseIndex);
Spin = 0;
SpinAngle = 0;
done = 0;
/*------------------------------------------------------------------------*/
/* This is our main loop for processing until the player exits or the */
/* game is completed (win or lose). */
/*------------------------------------------------------------------------*/
while (!done)
{
if (LastSeconds != tmSeconds)
{
ShowTime();
LastSeconds = tmSeconds;
if (tmHours == 0 && tmMinutes == 0 && tmSeconds == 0)
{
LostFlag = 1;
break;
}
}
/*------------------------------------------------------------------------*/
/* Call the routine to change any wall tiles that need changing. */
/*------------------------------------------------------------------------*/
AnimateWalls();
/*------------------------------------------------------------------------*/
/* Update the location of the energy bolt if it was fired. */
/*------------------------------------------------------------------------*/
if (Shooting)
UpdateBomb();
UpdateWallBolt();
UpdateSpaceMen();
/*------------------------------------------------------------------------*/
/* Call the engine to animate objects and then build the scene */
/*------------------------------------------------------------------------*/
AckCheckObjectMovement(ae);
AckBuildView(ae);
AckDrawOverlay(ae->ScreenBuffer,ae->OverlayBuffer);
ShowCompass();
i = 0;
mouse_read_cursor(&mbuttons,&my,&mx);
if (mx >= VP_STARTX-14 && mx <= VP_ENDX && my >= 0 && my <= VP_ENDY)
{
mouse_hide_cursor();
i = 1;
}
if (InventoryFlag)
ShowInventory();
if (LockedFlag)
{
smWriteHUD(155,100,15,"LOCKED");
LockedFlag = 0;
}
AckDisplayScreen(ae);
if (!MouseMode)
CheckMouseCursor(mx,my);
if (i)
mouse_show_cursor();
/*------------------------------------------------------------------------*/
/* Check open/close status of doors and play appropriate sounds */
/*------------------------------------------------------------------------*/
PlayDoorSounds();
if (!BoltEnergy)
{
LostFlag = 1;
break;
}
if (YouWON)
break;
/*------------------------------------------------------------------------*/
/* Check to see if decompression has occurred in the station! */
/*------------------------------------------------------------------------*/
if (Decompress)
{
AppPlaySound(SOUND_HITWALL); /* Change to decompress sound! */
ShowColor(4);
delay(500);
ShowColor(64+4);
delay(500);
ShowColor(128+4);
delay(500);
ShowColor(192+4);
delay(1000);
LostFlag = 1;
break;
}
if (Spin)
{
Spin >>= 1;
ae->PlayerAngle += SpinAngle;
if (ae->PlayerAngle >= INT_ANGLE_360)
ae->PlayerAngle -= INT_ANGLE_360;
if (ae->PlayerAngle < 0)
ae->PlayerAngle += INT_ANGLE_360;
}
/*------------------------------------------------------------------------*/
/* We'll allow two different modes of operation of the mouse. In mode 0 */
/* below a mouse cursor will be displayed and change shape depending on */
/* what area of the viewport it is on. Mode 1 below will use the movement */
/* of the mouse to move the POV ala Wolf-3D. Only mode 0 will allow the */
/* player to select icons for various actions. */
/*------------------------------------------------------------------------*/
if (!MouseMode)
{
mouse_read_cursor(&mbuttons,&my,&mx);
if (mbuttons & 1)
{
switch (LastMouseIndex)
{
case MOUSE_ARROW:
break;
case MOUSE_UPARROW:
j = AckMovePOV(ae,ae->PlayerAngle,16);
if (j == POV_XWALL || j == POV_YWALL)
AppPlaySound(SOUND_HITWALL);
if (j == POV_OBJECT)
CheckOurObjects();
j = AckCheckDoorOpen(ae->xPlayer,
ae->yPlayer,
ae->PlayerAngle,ae);
/* Do something if door is locked */
if (j & POV_DOORLOCKED)
LockedFlag = 1;
CheckPlayerSquare();
break;
case MOUSE_DNARROW:
j = ae->PlayerAngle + INT_ANGLE_180;
if (j >= INT_ANGLE_360)
j -= INT_ANGLE_360;
i = AckMovePOV(ae,j,16);
if (i == POV_XWALL || i == POV_YWALL)
AppPlaySound(SOUND_HITWALL);
break;
case MOUSE_LTARROW:
SpinAngle = -INT_ANGLE_4;
Spin = 1;
break;
case MOUSE_RTARROW:
SpinAngle = INT_ANGLE_4;
Spin = 1;
break;
default:
break;
}
/*------------------------------------------------------------------------*/
/* Now check to see if the mouse has hit one of the icons */
/*------------------------------------------------------------------------*/
if (mx >= 10 && mx <= 131 && my >= 131 && my <= 139) /* Inventory */
{
mouse_released();
InventoryFlag ^= 1;
}
if (mx >= 28 && mx <= 45 && my >= 142 && my <= 150) /* Map icon */
{
mouse_released();
ShowOverhead();
}
if (mx >= 292 && mx <= 312 && my >= 131 && my <= 139) /* Help */
{
mouse_released();
ShowInstructions();
}
if (mx >= 273 && mx <= 295 && my >= 142 && my <= 150) /* Drop */
{
mouse_released();
DropObject();
}
}
}
else
{
CheckMouse(&mouse);
if (mouse.mdx < 0)
{
Spin = -mouse.mdx;
Spin >>= 3;
SpinAngle = -INT_ANGLE_2 * Spin;
Spin = 1;
}
if (mouse.mdx > 0)
{
Spin = mouse.mdx;
Spin >>= 3;
SpinAngle = INT_ANGLE_2 * Spin;
Spin = 1;
}
if (mouse.mdy < 0)
{
i = -mouse.mdy;
i >>= 2;
i += 16;
j = AckMovePOV(ae,ae->PlayerAngle,i);
if (j == POV_XWALL || j == POV_YWALL)
AppPlaySound(SOUND_HITWALL);
if (j == POV_OBJECT)
CheckOurObjects();
j = AckCheckDoorOpen(ae->xPlayer,ae->yPlayer,ae->PlayerAngle,ae);
if (j & POV_DOORLOCKED)
LockedFlag = 1;
CheckPlayerSquare();
}
if (mouse.mdy > 0)
{
i = mouse.mdy;
i >>= 2;
i += 16;
j = ae->PlayerAngle + INT_ANGLE_180;
if (j >= INT_ANGLE_360)
j -= INT_ANGLE_360;
i = AckMovePOV(ae,j,i);
if (i == POV_XWALL || i == POV_YWALL)
AppPlaySound(SOUND_HITWALL);
}
}
/*------------------------------------------------------------------------*/
/* The right button or spacebar activates doors */
/*------------------------------------------------------------------------*/
if ((mbuttons & 2) || (Keys[SPACEBAR_KEY]))
{
if (BoltEnergy)
{
i = MAX_OBJECTS-1;
if (!ae->ObjList[i].Active)
{
AppPlaySound(SOUND_FIRING);
ae->ObjList[i].x = ae->xPlayer;
ae->ObjList[i].y = ae->yPlayer;
ae->ObjList[i].Dir = ae->PlayerAngle;
ae->ObjList[i].mPos = (ae->yPlayer & 0xFFC0) + (ae->xPlayer >> 6);
ae->ObjList[i].VidRow = 160;
ae->ObjList[i].Active = 1;
Shooting = 1;
BoltEnergy--;
mouse_hide_cursor();
ShowLightbar();
mouse_show_cursor();
}
}
}
/*------------------------------------------------------------------------*/
/* The keyboard is now checked. */
/*------------------------------------------------------------------------*/
if(Keys[ESCAPE_KEY])
break;
if(Keys[RIGHT_ARROW_KEY])
{
Spin += 2;
SpinAngle = INT_ANGLE_2 * Spin;
}
if(Keys[LEFT_ARROW_KEY])
{
Spin += 2;
SpinAngle = -INT_ANGLE_2 * Spin;
}
if(Keys[UP_ARROW_KEY])
{
j = AckMovePOV(ae,ae->PlayerAngle,16);
if (j == POV_XWALL || j == POV_YWALL)
AppPlaySound(SOUND_HITWALL);
if (j == POV_OBJECT)
CheckOurObjects();
j = AckCheckDoorOpen(ae->xPlayer,ae->yPlayer,ae->PlayerAngle,ae);
if (j & POV_DOORLOCKED)
LockedFlag = 1;
CheckPlayerSquare();
}
if(Keys[DOWN_ARROW_KEY])
{
j = ae->PlayerAngle + INT_ANGLE_180;
if (j >= INT_ANGLE_360)
j -= INT_ANGLE_360;
j = AckMovePOV(ae,j,16);
if (j == POV_XWALL || j == POV_YWALL)
AppPlaySound(SOUND_HITWALL);
if (j == POV_OBJECT)
CheckOurObjects();
CheckPlayerSquare();
}
if (Keys[F1_KEY])
{
MouseMode ^= 1;
while (Keys[F1_KEY]);
if (!MouseMode)
mouse_show_cursor();
else
mouse_hide_cursor();
}
if (Keys[LETTER_I_KEY])
{
InventoryFlag ^= 1;
while (Keys[LETTER_I_KEY]);
}
if (Keys[LETTER_L_KEY])
{
ae->LightFlag ^= 1;
}
if (Keys[LETTER_M_KEY])
{
while (Keys[LETTER_M_KEY]);
ShowOverhead();
}
if (Keys[LETTER_H_KEY])
{
while (Keys[LETTER_H_KEY]);
ShowInstructions();
}
if (Keys[LETTER_D_KEY])
{
while (Keys[LETTER_D_KEY]);
DropObject();
}
if (Keys[LETTER_S_KEY])
{
while (Keys[LETTER_S_KEY]);
if (!NoMusic)
{
if (MusicFlag)
{
AckStopBackground();
MusicFlag = 0;
}
}
}
/*------------------------------------------------------------------------*/
/* This is some test code put in to try different players in the same */
/* map. The number keys 1,2,3 activate 3 different players that all start */
/* out in the same place but at different angles. By moving a player and */
/* then pressing 1,2,3 the new player can walk around and see the other */
/* players as space-suited characters. Not all in yet, but its a start. */
/*------------------------------------------------------------------------*/
if (Keys[NUMBER_1_KEY] ||
Keys[NUMBER_2_KEY] ||
Keys[NUMBER_3_KEY])
{
Views[ViewNum].xP = ae->xPlayer;
Views[ViewNum].yP = ae->yPlayer;
Views[ViewNum].Angle = ae->PlayerAngle;
ae->ObjList[ViewNum+5].x = ae->xPlayer;
ae->ObjList[ViewNum+5].y = ae->yPlayer;
ae->ObjList[ViewNum+5].Active = 1;
j = (ae->ObjList[ViewNum+5].y & 0xFFC0) + (ae->ObjList[ViewNum+5].x >> 6);
if (Keys[NUMBER_1_KEY])
ViewNum = 0;
if (Keys[NUMBER_2_KEY])
ViewNum = 1;
if (Keys[NUMBER_3_KEY])
ViewNum = 2;
ae->xPlayer = Views[ViewNum].xP;
ae->yPlayer = Views[ViewNum].yP;
ae->PlayerAngle = Views[ViewNum].Angle;
ae->ObjList[ViewNum+5].x = ae->xPlayer;
ae->ObjList[ViewNum+5].y = ae->yPlayer;
ae->ObjList[ViewNum+5].Active = 0;
j = (ae->ObjList[ViewNum+5].y & 0xFFC0) + (ae->ObjList[ViewNum+5].x >> 6);
}
}
setvect(KEYBD,oldvec);
setvect(0x1C,OldTimer);
/*------------------------------------------------------------------------*/
/* Here if time ran out, meaning the game has been lost. */
/*------------------------------------------------------------------------*/
if (LostFlag)
{
YouWON = 0;
if (!Decompress)
{
if (BoltEnergy)
ShowTextFile("lost.txt");
else
ShowTextFile("lost1.txt");
}
else
ShowTextFile("decomp.txt");
AppPlaySound(SOUND_LOST);
i = 3000;
while (i)
{
if (kbhit())
{
getch();
break;
}
delay(10);
i--;
}
AckFadeOut(0,255);
}
if (YouWON)
{
ShowTextFile("won.txt");
AppPlaySound(SOUND_USER3);
i = 3000;
while (i)
{
if (kbhit())
{
getch();
break;
}
delay(10);
i--;
}
AckFadeOut(0,255);
}
AckWrapUp(ae);
#if USE_SOUND
AckSoundShutdown();
#endif
AckSetTextmode();
return(0);
}